using System;
using CLELCore.Assembly.StreamTables;
using CLELCore.Assembly.BlobStreams;

namespace CLELCore.Assembly
{
	public static class TokenDecompressor
	{
		public const int ONE_BIT_TAG_MAX = 32768; //2^(16-1)		
		public const int TWO_BIT_TAG_MAX = 16384; //2^(16-2)		
		public const int THREE_BIT_TAG_MAX = 8192; //2^(16-3)		
		public const int FIVE_BIT_TAG_MAX = 2048; //2^(16-5)		

		//TypeDefOrRef
		public const int TYPEDEFORREF_TYPEDEF = 0x0;
		public const int TYPEDEFORREF_TYPEREF = 0x1;
		public const int TYPEDEFORREF_TYPESPEC = 0x2;

		//HasConstant
		public const int HASCONSTANT_FIELD = 0x0;
		public const int HASCONSTANT_PARAM = 0x1;
		public const int HASCONSTANT_PROPERTY = 0x2;

		//HasCustomAttribute
		public const int HASCUSTOMATTRIBUTE_METHODDEF = 0x0;
		public const int HASCUSTOMATTRIBUTE_FIELD = 0x1;
		public const int HASCUSTOMATTRIBUTE_TYPEREF = 0x2;
		public const int HASCUSTOMATTRIBUTE_TYPEDEF = 0x3;
		public const int HASCUSTOMATTRIBUTE_PARAM = 0x4;
		public const int HASCUSTOMATTRIBUTE_INTERFACEIMPL = 0x5;
		public const int HASCUSTOMATTRIBUTE_MEMBERREF = 0x6;
		public const int HASCUSTOMATTRIBUTE_MODULE = 0x7;
		public const int HASCUSTOMATTRIBUTE_DECLSECURITY = 0x8;
		public const int HASCUSTOMATTRIBUTE_PROPERTY = 0x9;
		public const int HASCUSTOMATTRIBUTE_EVENT = 0xa;
		public const int HASCUSTOMATTRIBUTE_STANDALONESIG = 0xb;
		public const int HASCUSTOMATTRIBUTE_MODULEREF = 0xc;
		public const int HASCUSTOMATTRIBUTE_TYPESPEC = 0xd;
		public const int HASCUSTOMATTRIBUTE_ASSEMBLY = 0xe;
		public const int HASCUSTOMATTRIBUTE_ASSEMBLYREF = 0xf;
		public const int HASCUSTOMATTRIBUTE_FILE = 0x10;
		public const int HASCUSTOMATTRIBUTE_EXPORTEDTYPE = 0x11;
		public const int HASCUSTOMATTRIBUTE_MANIFESTRESOURCE = 0x12;
		
		//CustomAttributeType
		public const int CUSTOMATTRIBUTETYPE_METHODDEF = 0x2;
		public const int CUSTOMATTRIBUTETYPE_MEMBERREF = 0x3;

		//HasDeclSecurity
		public const int HASDECLSECURITY_TYPEDEF = 0x0;
		public const int HASDECLSECURITY_METHODDEF = 0x1;
		public const int HASDECLSECURITY_ASSEMBLY = 0x2;

		//MemberForwarded
		public const int MEMBERFORWARDED_FIELD = 0x0;
		public const int MEMBERFORWARDED_METHODDEF = 0x1;

		//Implementation
		public const int IMPLEMENTATION_FILE = 0x0;
		public const int IMPLEMENTATION_ASSEMBLYREF = 0x1;
		public const int IMPLEMENTATION_EXPORTEDTYPE = 0x2;

		//MethodDefOrRef
		public const int METHODDEFORREF_METHODDEF = 0x0;
		public const int METHODDEFORREF_MEMBERREF = 0x1;

		//HasSemantics
		public const int HASSEMANTICS_EVENT = 0x0;
		public const int HASSEMANTICS_PROPERTY = 0x1;

		//MemberRefParent
		public const int MEMBERREFPARENT_TYPEREF = 0x1;
		public const int MEMBERREFPARENT_MODULEREF = 0x2;
		public const int MEMBERREFPARENT_METHODDEF = 0x3;
		public const int MEMBERREFPARENT_TYPESPEC = 0x4;
	
		//ResolutionScope
		public const int RESOLUTIONSCOPE_MODULE = 0x0;
		public const int RESOLUTIONSCOPE_MODULEREF = 0x1;
		public const int RESOLUTIONSCOPE_ASSEMBLYREF = 0x2;
		public const int RESOLUTIONSCOPE_TYPEREF = 0x3;

		//TypeOrMethodDef
		public const int TYPEORMETHODDEF_TYPEDEF = 0x0;
		public const int TYPEORMETHODDEF_METHODDEF = 0x1;
		
		//HasFieldMarshall
		public const int HASFIELDMARSHALL_FIELD = 0x0;
		public const int HASFIELDMARSHALL_PARAM = 0x1;

		public static Token DecompressTypeDefOrRefToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.TYPEDEF_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.TYPEREF_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.TYPESPEC_TABLE] < TWO_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == TYPEDEFORREF_TYPEDEF)
			{
				return new Token(StreamTable.TYPEDEF_TABLE,row);
			}
			else if(type == TYPEDEFORREF_TYPEREF)
			{
				return new Token(StreamTable.TYPEREF_TABLE,row);
			}
			else if(type == TYPEDEFORREF_TYPESPEC)
			{
				return new Token(StreamTable.TYPESPEC_TABLE,row);
			}
			return null;
		}
		
		public static Token DecompressBlobTypeDefOrRefToken(byte[] bytes,ref int offset)
		{
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = Blob.DecompressBlobValue(bytes,ref offset);
			
			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == TYPEDEFORREF_TYPEDEF)
			{
				return new Token(StreamTable.TYPEDEF_TABLE,row);
			}
			else if(type == TYPEDEFORREF_TYPEREF)
			{
				return new Token(StreamTable.TYPEREF_TABLE,row);
			}
			else if(type == TYPEDEFORREF_TYPESPEC)
			{
				return new Token(StreamTable.TYPESPEC_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressHasConstantToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.FIELD_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.PARAM_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.PROPERTY_TABLE] < TWO_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == HASCONSTANT_FIELD)
			{
				return new Token(StreamTable.FIELD_TABLE,row);
			}
			else if(type == HASCONSTANT_PARAM)
			{
				return new Token(StreamTable.PARAM_TABLE,row);
			}
			else if(type == HASCONSTANT_PROPERTY)
			{
				return new Token(StreamTable.PROPERTY_TABLE,row);
			}
			return null;
		}
		
		public static Token DecompressHasCustomAttributeToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.METHODDEF_TABLE] < FIVE_BIT_TAG_MAX && 
				table_rows[StreamTable.FIELD_TABLE] < FIVE_BIT_TAG_MAX && 
				table_rows[StreamTable.TYPEREF_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.TYPEDEF_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.PARAM_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.INTERFACEIMPL_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.MEMBERREF_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.MODULE_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.DECLSECURITY_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.PROPERTY_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.EVENT_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.STANDALONESIG_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.MODULEREF_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.TYPESPEC_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.ASSEMBLY_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.ASSEMBLYREF_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.FILE_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.EXPORTEDTYPE_TABLE] < FIVE_BIT_TAG_MAX &&
				table_rows[StreamTable.MANIFESTRESOURCE_TABLE] < FIVE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,4,tok);
			int row = tok>>5;
			if(type == HASCUSTOMATTRIBUTE_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_FIELD)
			{
				return new Token(StreamTable.FIELD_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_TYPEREF)
			{
				return new Token(StreamTable.TYPEREF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_TYPEDEF)
			{
				return new Token(StreamTable.TYPEDEF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_PARAM)
			{
				return new Token(StreamTable.PARAM_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_INTERFACEIMPL)
			{
				return new Token(StreamTable.INTERFACEIMPL_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_MEMBERREF)
			{
				return new Token(StreamTable.MEMBERREF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_MODULE)
			{
				return new Token(StreamTable.MODULE_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_DECLSECURITY)
			{
				return new Token(StreamTable.DECLSECURITY_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_PROPERTY)
			{
				return new Token(StreamTable.PROPERTY_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_EVENT)
			{
				return new Token(StreamTable.EVENT_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_STANDALONESIG)
			{
				return new Token(StreamTable.STANDALONESIG_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_MODULEREF)
			{
				return new Token(StreamTable.MODULEREF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_TYPESPEC)
			{
				return new Token(StreamTable.TYPESPEC_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_ASSEMBLY)
			{
				return new Token(StreamTable.ASSEMBLY_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_ASSEMBLYREF)
			{
				return new Token(StreamTable.ASSEMBLYREF_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_FILE)
			{
				return new Token(StreamTable.FILE_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_EXPORTEDTYPE)
			{
				return new Token(StreamTable.EXPORTEDTYPE_TABLE,row);
			}
			else if(type == HASCUSTOMATTRIBUTE_MANIFESTRESOURCE)
			{
				return new Token(StreamTable.MANIFESTRESOURCE_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressCustomAttributeTypeToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.METHODDEF_TABLE] < THREE_BIT_TAG_MAX && 
				table_rows[StreamTable.MEMBERREF_TABLE] < THREE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}

			int type = Bits.GetBits(0,2,tok);
			int row = tok>>3;
			if(type == CUSTOMATTRIBUTETYPE_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}
			else if(type == CUSTOMATTRIBUTETYPE_MEMBERREF)
			{
				return new Token(StreamTable.MEMBERREF_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressHasDeclSecurityToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.TYPEDEF_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.METHODDEF_TABLE] < TWO_BIT_TAG_MAX &&
				table_rows[StreamTable.ASSEMBLY_TABLE] < TWO_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}

			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == HASDECLSECURITY_TYPEDEF)
			{
				return new Token(StreamTable.TYPEDEF_TABLE,row);
			}
			else if(type == HASDECLSECURITY_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}
			else if(type == HASDECLSECURITY_ASSEMBLY)
			{
				return new Token(StreamTable.ASSEMBLY_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressMemberForwardedToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.FIELD_TABLE] < ONE_BIT_TAG_MAX && 
				table_rows[StreamTable.METHODDEF_TABLE] < ONE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,0,tok);
			int row = tok>>1;
			if(type == MEMBERFORWARDED_FIELD)
			{
				return new Token(StreamTable.FIELD_TABLE,row);
			}
			else if(type == MEMBERFORWARDED_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressImplementationToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.FILE_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.ASSEMBLYREF_TABLE] < TWO_BIT_TAG_MAX &&
				table_rows[StreamTable.EXPORTEDTYPE_TABLE] < TWO_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == IMPLEMENTATION_FILE)
			{
				return new Token(StreamTable.FILE_TABLE,row);
			}
			else if(type == IMPLEMENTATION_ASSEMBLYREF)
			{
				return new Token(StreamTable.ASSEMBLYREF_TABLE,row);
			}
			else if(type == IMPLEMENTATION_EXPORTEDTYPE)
			{
				return new Token(StreamTable.EXPORTEDTYPE_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressMethodDefOrRefToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.METHODDEF_TABLE] < ONE_BIT_TAG_MAX && 
				table_rows[StreamTable.MEMBERREF_TABLE] < ONE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,0,tok);
			int row = tok>>1;
			if(type == METHODDEFORREF_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}
			else if(type == METHODDEFORREF_MEMBERREF)
			{
				return new Token(StreamTable.MEMBERREF_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressHasSemanticsToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.EVENT_TABLE] < ONE_BIT_TAG_MAX && 
				table_rows[StreamTable.PROPERTY_TABLE] < ONE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,0,tok);
			int row = tok>>1;
			if(type == HASSEMANTICS_EVENT)
			{
				return new Token(StreamTable.EVENT_TABLE,row);
			}
			else if(type == HASSEMANTICS_PROPERTY)
			{
				return new Token(StreamTable.PROPERTY_TABLE,row);
			}
			
			return null;
		}
		
		public static Token DecompressMemberRefParentToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.TYPEREF_TABLE] < THREE_BIT_TAG_MAX && 
				table_rows[StreamTable.MODULEREF_TABLE] < THREE_BIT_TAG_MAX && 
				table_rows[StreamTable.METHODDEF_TABLE] < THREE_BIT_TAG_MAX && 
				table_rows[StreamTable.TYPESPEC_TABLE] < THREE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
		
			int type = Bits.GetBits(0,2,tok);
			int row = tok>>3;
			if(type == MEMBERREFPARENT_TYPEREF)
			{
				return new Token(StreamTable.TYPEREF_TABLE,row);
			}
			else if(type == MEMBERREFPARENT_MODULEREF)
			{
				return new Token(StreamTable.MODULEREF_TABLE,row);
			}
			else if(type == MEMBERREFPARENT_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}
			else if(type == MEMBERREFPARENT_TYPESPEC)
			{
				return new Token(StreamTable.TYPESPEC_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressResolutionScopeToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.MODULE_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.MODULEREF_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.ASSEMBLYREF_TABLE] < TWO_BIT_TAG_MAX && 
				table_rows[StreamTable.TYPEREF_TABLE] < TWO_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,1,tok);
			int row = tok>>2;
			if(type == RESOLUTIONSCOPE_MODULE)
			{
				return new Token(StreamTable.MODULE_TABLE,row);
			}
			else if(type == RESOLUTIONSCOPE_MODULEREF)
			{
				return new Token(StreamTable.MODULEREF_TABLE,row);
			}
			else if(type == RESOLUTIONSCOPE_ASSEMBLYREF)
			{
				return new Token(StreamTable.ASSEMBLYREF_TABLE,row);
			}
			else if(type == RESOLUTIONSCOPE_TYPEREF)
			{
				return new Token(StreamTable.TYPEREF_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressTypeOrMethodDefToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.TYPEDEF_TABLE] < ONE_BIT_TAG_MAX && 
				table_rows[StreamTable.METHODDEF_TABLE] < ONE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,0,tok);
			int row = tok>>1;
			if(type == TYPEORMETHODDEF_TYPEDEF)
			{
				return new Token(StreamTable.TYPEDEF_TABLE,row);
			}
			else if(type == TYPEORMETHODDEF_METHODDEF)
			{
				return new Token(StreamTable.METHODDEF_TABLE,row);
			}

			return null;
		}
		
		public static Token DecompressHasFieldMarshallToken(int[] table_rows,byte[] bytes,ref int offset)
		{
			if(table_rows == null)
				throw new ArgumentException("Table Rows cannot be null");
			if(bytes == null)
				throw new ArgumentException("Bytes cannot be null");
			int tok = 0;
			if(table_rows[StreamTable.FIELD_TABLE] < ONE_BIT_TAG_MAX && 
				table_rows[StreamTable.PARAM_TABLE] < ONE_BIT_TAG_MAX)
			{
				if(offset + 2 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse two bytes");
				}
				//two bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],0,0);
				offset += 2;
			}
			else
			{
				if(offset + 4 >= bytes.Length || offset < 0)
				{
					throw new ArgumentException("Bytes not long enough trying to parse four bytes");
				}
				//four bytes
				tok = Bits.MakeInt(bytes[offset],bytes[offset+1],bytes[offset+2],bytes[offset+3]);
				offset += 4;
			}
			
			int type = Bits.GetBits(0,0,tok);
			int row = tok>>1;
			if(type == HASFIELDMARSHALL_FIELD)
			{
				return new Token(StreamTable.FIELD_TABLE,row);
			}
			else if(type == HASFIELDMARSHALL_PARAM)
			{
				return new Token(StreamTable.PARAM_TABLE,row);
			}
			
			return null;
		}
	}
}
